#include "downloader_window.h"
#include "downloader_logic.h" // Include the logic header
#include <iostream>           // For cerr/cout debugging
#include <gtkmm/messagedialog.h>

DownloaderWindow::DownloaderWindow() : m_main_vbox(Gtk::ORIENTATION_VERTICAL, 10), // Spacing 10px
                                       m_grid(),
                                       m_url_label("URL:"),
                                       m_threads_label("Threads:"),
                                       m_save_path_label("Save As:"),
                                       m_save_path_button("Select File...", Gtk::FILE_CHOOSER_ACTION_SAVE),
                                       m_progress_hbox(Gtk::ORIENTATION_HORIZONTAL, 5),
                                       m_status_label("Idle"),
                                       m_button_hbox(Gtk::ORIENTATION_HORIZONTAL, 10),
                                       m_start_button("Start Download"),
                                       m_cancel_button("Cancel"),
                                       m_cancel_requested(false)
{
    // --- Window Settings ---
    set_title("Gtkmm 多线程下载器");
    set_default_size(650, 280);
    set_border_width(15); // 增加窗口边距

    // --- Configure Widgets ---
    m_url_entry.set_placeholder_text("请输入下载链接...");
    m_url_entry.set_width_chars(40);     // 设置URL输入框宽度
    m_url_entry.set_max_width_chars(80); // 最大宽度限制
    m_url_entry.set_hexpand(true);       // 水平方向可扩展

    m_threads_spinbutton.set_range(1, 32);     // 最小1线程，最大32线程
    m_threads_spinbutton.set_value(4);         // 默认4线程
    m_threads_spinbutton.set_increments(1, 5); // 步进1，页步进5
    m_threads_spinbutton.set_width_chars(5);   // 设置线程输入框宽度

    m_save_path_button.set_current_name("downloaded_file"); // 默认文件名
    m_save_path_button.set_hexpand(true);                   // 水平方向可扩展

    // 美化进度条
    m_progress_bar.set_halign(Gtk::ALIGN_FILL);
    m_progress_bar.set_hexpand(true);     // 进度条填充水平空间
    m_progress_bar.set_margin_top(10);    // 顶部边距
    m_progress_bar.set_margin_bottom(10); // 底部边距

    // 状态标签左对齐
    m_status_label.set_halign(Gtk::ALIGN_START);
    m_status_label.set_margin_left(5); // 左侧边距

    // 美化按钮
    m_start_button.set_margin_left(5);    // 左侧边距
    m_start_button.set_margin_right(5);   // 右侧边距
    m_cancel_button.set_margin_left(5);   // 左侧边距
    m_cancel_button.set_margin_right(5);  // 右侧边距
    m_cancel_button.set_sensitive(false); // 初始禁用

    // --- Layout ---
    // 网格布局的输入区域
    m_grid.set_row_spacing(10);    // 增加行间距
    m_grid.set_column_spacing(15); // 增加列间距
    m_grid.set_margin_bottom(15);  // 底部边距

    // 标签右对齐
    m_url_label.set_halign(Gtk::ALIGN_END);
    m_threads_label.set_halign(Gtk::ALIGN_END);
    m_save_path_label.set_halign(Gtk::ALIGN_END);

    m_grid.attach(m_url_label, 0, 0, 1, 1); // 列, 行, 宽度, 高度
    m_grid.attach(m_url_entry, 1, 0, 1, 1);
    m_grid.attach(m_threads_label, 0, 1, 1, 1);
    m_grid.attach(m_threads_spinbutton, 1, 1, 1, 1);
    m_grid.attach(m_save_path_label, 0, 2, 1, 1);
    m_grid.attach(m_save_path_button, 1, 2, 1, 1);
    m_grid.set_halign(Gtk::ALIGN_CENTER); // 网格居中对齐
    m_grid.set_hexpand(true);             // 水平方向可扩展

    // 进度条和状态标签
    m_progress_hbox.set_margin_top(5);                                   // 顶部边距
    m_progress_hbox.set_margin_bottom(10);                               // 底部边距
    m_progress_hbox.pack_start(m_progress_bar, Gtk::PACK_EXPAND_WIDGET); // 进度条填充可用空间
    m_progress_hbox.pack_start(m_status_label, Gtk::PACK_SHRINK);        // 标签只占需要的空间

    // 按钮
    m_button_hbox.set_halign(Gtk::ALIGN_CENTER); // 按钮水平居中
    m_button_hbox.set_margin_top(5);             // 顶部边距
    m_button_hbox.set_spacing(20);               // 增加按钮间距
    m_button_hbox.pack_start(m_start_button, Gtk::PACK_SHRINK);
    m_button_hbox.pack_start(m_cancel_button, Gtk::PACK_SHRINK);

    // 主垂直布局盒子
    m_main_vbox.set_spacing(10);                               // 增加垂直间距
    m_main_vbox.set_margin_bottom(10);                         // 底部边距
    m_main_vbox.set_border_width(10);                          // 边框宽度
    m_main_vbox.pack_start(m_grid, Gtk::PACK_SHRINK);          // 网格在顶部
    m_main_vbox.pack_start(m_progress_hbox, Gtk::PACK_SHRINK); // 进度条在网格下方
    m_main_vbox.pack_start(m_button_hbox, Gtk::PACK_SHRINK);   // 按钮在底部

    // 使主布局居中
    m_main_vbox.set_halign(Gtk::ALIGN_CENTER);
    m_main_vbox.set_valign(Gtk::ALIGN_CENTER);

    // 将主盒子添加到窗口
    // 在gtkmm 4.0中，使用set_child()
    add(m_main_vbox);

    // --- Connect Signals ---
    m_start_button.signal_clicked().connect(sigc::mem_fun(*this, &DownloaderWindow::on_start_button_clicked));
    m_cancel_button.signal_clicked().connect(sigc::mem_fun(*this, &DownloaderWindow::on_cancel_button_clicked));
    m_dispatcher.connect(sigc::mem_fun(*this, &DownloaderWindow::on_update_notification));

    // Show all widgets
    show_all_children();
}

DownloaderWindow::~DownloaderWindow()
{
    std::cout << "DownloaderWindow destructor called." << std::endl;
    // Ensure the background thread is properly joined before the window is destroyed
    if (m_download_thread.joinable())
    {
        std::cout << "Attempting to cancel and join download thread..." << std::endl;
        m_cancel_requested = true; // Signal cancellation
        // Give the thread a chance to react to cancellation before joining
        // This might need refinement depending on how blocking the thread can be
        m_download_thread.join();
        std::cout << "Download thread joined." << std::endl;
    }
    m_downloader_logic.reset(); // Release the logic object
    std::cout << "Downloader logic reset." << std::endl;
}

// Override close request handler
bool DownloaderWindow::on_delete_event(GdkEventAny *event)
{
    bool is_running;
    { // Lock scope
        std::lock_guard<std::mutex> lock(m_ui_data_mutex);
        is_running = m_ui_data.is_running;
    }

    if (is_running)
    {
        Gtk::MessageDialog dialog(*this, "Download in Progress", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
        dialog.set_secondary_text("A download is currently running. Are you sure you want to cancel it and exit?");
        int result = dialog.run();
        if (result == Gtk::RESPONSE_YES)
        {
            std::cout << "User chose to exit while download running. Cancelling..." << std::endl;
            on_cancel_button_clicked(); // Request cancel
            // Let the destructor handle joining the thread
            return false; // Allow window to close (destructor will run)
        }
        else
        {
            return true; // Prevent window from closing
        }
    }
    return false; // Allow window to close if not running
}

void DownloaderWindow::on_start_button_clicked()
{
    bool is_running;
    { // Lock scope
        std::lock_guard<std::mutex> lock(m_ui_data_mutex);
        is_running = m_ui_data.is_running;
    }

    if (is_running)
    {
        std::cerr << "Start clicked while already running!" << std::endl;
        return; // Should not happen if button is disabled, but check anyway
    }

    // --- Get Inputs ---
    std::string url = m_url_entry.get_text();
    int num_threads = m_threads_spinbutton.get_value_as_int();
    // Gtk::FileChooserButton provides the full path directly
    std::string save_path = m_save_path_button.get_filename();

    // --- Basic Input Validation ---
    if (url.empty())
    {
        Gtk::MessageDialog dialog(*this, "Error", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        dialog.set_secondary_text("Please enter a valid URL.");
        dialog.run();
        return;
    }
    if (save_path.empty())
    {
        Gtk::MessageDialog dialog(*this, "Error", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        dialog.set_secondary_text("Please select a valid save location.");
        dialog.run();
        return;
    }
    // Check if save path is directory (FileChooserButton in SAVE mode usually prevents this)
    if (Glib::file_test(save_path, Glib::FILE_TEST_IS_DIR))
    {
        Gtk::MessageDialog dialog(*this, "Error", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        dialog.set_secondary_text("Selected save path is a directory, please specify a filename.");
        dialog.run();
        return;
    }

    // --- Reset State & UI ---
    if (m_download_thread.joinable())
    {
        m_download_thread.join(); // Join previous thread if any (shouldn't be needed if logic is correct)
    }
    m_downloader_logic.reset(); // Delete previous logic object
    m_cancel_requested = false;
    { // Lock scope
        std::lock_guard<std::mutex> lock(m_ui_data_mutex);
        m_ui_data.reset();
        m_ui_data.is_running = true;
        m_ui_data.status_message = "Starting...";
    }
    m_start_button.set_sensitive(false);
    m_cancel_button.set_sensitive(true);
    m_url_entry.set_sensitive(false);
    m_threads_spinbutton.set_sensitive(false);
    m_save_path_button.set_sensitive(false);
    update_ui_widgets(); // Show "Starting..." message

    // --- Create Logic Object & Start Thread ---
    try
    {
        // Pass references needed by the logic thread
        m_downloader_logic = std::make_unique<DownloaderLogic>(
            url,
            save_path,
            num_threads,
            m_cancel_requested, // Share the atomic flag
            m_dispatcher,       // Share the dispatcher
            m_ui_data,          // Share the data structure
            m_ui_data_mutex     // Share the mutex
        );

        // Start the download logic in a separate thread
        m_download_thread = std::thread(&DownloaderLogic::run_download, m_downloader_logic.get());
    }
    catch (const std::exception &e)
    {
        std::cerr << "Error creating DownloaderLogic or thread: " << e.what() << std::endl;
        { // Lock scope
            std::lock_guard<std::mutex> lock(m_ui_data_mutex);
            m_ui_data.reset(); // Reset state
            m_ui_data.has_error = true;
            m_ui_data.error_message = std::string("Initialization failed: ") + e.what();
            m_ui_data.status_message = "Error";
        }
        on_update_notification(); // Trigger UI update to show error state
    }
}

void DownloaderWindow::on_cancel_button_clicked()
{
    bool was_running = false;
    { // Lock scope
        std::lock_guard<std::mutex> lock(m_ui_data_mutex);
        if (m_ui_data.is_running)
        {
            was_running = true;
            m_ui_data.status_message = "Cancelling...";
        }
    }

    if (was_running)
    {
        m_cancel_requested = true;            // Signal the logic thread to cancel
        m_cancel_button.set_sensitive(false); // Disable cancel button after click
        update_ui_widgets();                  // Show "Cancelling..."
        std::cout << "Cancel requested." << std::endl;
    }
    else
    {
        std::cerr << "Cancel clicked but not running!" << std::endl;
    }
}

void DownloaderWindow::on_update_notification()
{
    // This function is guaranteed to run in the GUI thread by Glib::Dispatcher
    update_ui_widgets();

    // Check if the download has finished or errored
    bool is_finished_or_error;
    bool has_error_flag;
    std::string final_message;
    std::string error_details;

    { // Lock scope
        std::lock_guard<std::mutex> lock(m_ui_data_mutex);
        is_finished_or_error = m_ui_data.is_finished || m_ui_data.has_error;
        has_error_flag = m_ui_data.has_error;
        if (is_finished_or_error)
        {
            m_ui_data.is_running = false; // Mark as no longer running
            final_message = m_ui_data.status_message;
            error_details = m_ui_data.error_message;
        }
    } // Mutex unlocks here

    // If finished or errored, join the thread and update UI state finally
    if (is_finished_or_error)
    {
        std::cout << "Detected finish/error in UI thread. Joining background thread..." << std::endl;
        if (m_download_thread.joinable())
        {
            m_download_thread.join();
            std::cout << "Background thread joined." << std::endl;
        }
        else
        {
            std::cerr << "Warning: Background thread was not joinable upon finish/error signal." << std::endl;
        }

        // Reset button states etc.
        m_start_button.set_sensitive(true);
        m_cancel_button.set_sensitive(false);
        m_url_entry.set_sensitive(true);
        m_threads_spinbutton.set_sensitive(true);
        m_save_path_button.set_sensitive(true);

        // Show final message dialog
        if (has_error_flag)
        {
            Gtk::MessageDialog dialog(*this, "Download Failed", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
            dialog.set_secondary_text(Glib::ustring::compose("Error: %1\nDetails: %2", final_message, error_details));
            dialog.run();
        }
        else
        {
            // Use INFO level for success
            Gtk::MessageDialog dialog(*this, "Download Complete", false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
            dialog.set_secondary_text(Glib::ustring::compose("Status: %1", final_message));
            dialog.run();
        }
    }
}

void DownloaderWindow::update_ui_widgets()
{
    // Lock the mutex to safely read the shared data
    std::lock_guard<std::mutex> lock(m_ui_data_mutex);

    // Update progress bar
    if (m_ui_data.total_size > 0)
    {
        m_progress_bar.set_fraction(m_ui_data.percentage);
        m_progress_bar.set_text(Glib::ustring::compose("%1%%", static_cast<int>(m_ui_data.percentage * 100.0)));
        m_progress_bar.set_show_text(true);
    }
    else if (m_ui_data.is_running && m_ui_data.total_size < 0)
    {
        // Indeterminate progress (unknown size)
        m_progress_bar.pulse(); // Make it pulse
        m_progress_bar.set_text("Downloading...");
        m_progress_bar.set_show_text(true);
    }
    else
    {
        // Idle or finished state
        m_progress_bar.set_fraction(m_ui_data.percentage); // Show 0% or 100%
        m_progress_bar.set_text(Glib::ustring::compose("%1%%", static_cast<int>(m_ui_data.percentage * 100.0)));
        m_progress_bar.set_show_text(true);
        if (!m_ui_data.is_running && !m_ui_data.is_finished && !m_ui_data.has_error)
        {
            m_progress_bar.set_text(""); // Clear text when truly idle
            m_progress_bar.set_show_text(false);
        }
    }

    // Update status label
    std::string status_text = m_ui_data.status_message;
    if (m_ui_data.is_running || m_ui_data.is_finished)
    {
        status_text += Glib::ustring::compose(" (%1 MB", m_ui_data.current_downloaded / (1024.0 * 1024.0));
        if (m_ui_data.total_size > 0)
        {
            status_text += Glib::ustring::compose(" / %1 MB)", m_ui_data.total_size / (1024.0 * 1024.0));
        }
        else
        {
            status_text += ")";
        }
    }
    else if (m_ui_data.has_error)
    {
        status_text = "Error: " + m_ui_data.status_message;
    }
    m_status_label.set_text(status_text);
}
